package com.acme.bankapp.net.bank;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import com.acme.bankapp.domain.bank.AbstractAccount;
import com.acme.bankapp.domain.bank.AccountExistsException;
import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.domain.bank.Client;
import com.acme.bankapp.domain.bank.ClientExistsException;
import com.acme.bankapp.service.bank.BankService;

import static com.acme.bankapp.net.bank.BankMessages.*;

public class BankServer implements Runnable {
	ServerSocket providerSocket;
	Socket connection;
	ObjectOutputStream out;
	ObjectInputStream in;
	private boolean isStopped;
	private BankService bankService;
	private Bank bank;
	private int port;
	
	public BankServer(int port) {
		this.port = port;
		bankService = new BankService();
		bank = new Bank();
	}
	
	@Override
	public void run() {
		try {
			// 1. creating a server socket
			providerSocket = new ServerSocket(port);
			// 2. Wait for connection
			System.out.println("Waiting for connection");
			connection = providerSocket.accept();
			System.out.println("Connection received from " + connection.getInetAddress().getHostName());
			// 3. get Input and Output streams
			out = new ObjectOutputStream(connection.getOutputStream());
			out.flush();
			in = new ObjectInputStream(connection.getInputStream());
			do {
				try {
					processMessage((String) in.readObject());
				} catch (ClassNotFoundException classnot) {
					System.err.println("Data received in unknown format");
				}
			} while (!isStopped);
		} catch (IOException ioException) {
			ioException.printStackTrace();
		} finally {
			// 4: Closing connection
			try {
				if (in != null)
					in.close();
				if (out != null)
					out.close();
				if (providerSocket != null)
					providerSocket.close();
			} catch (IOException ioException) {
				ioException.printStackTrace();
			}
		}
	}
	
	void processMessage(String msg) {
		try {
			switch(msg) {
			case BMSG_CLIENT_ADD:
				bankService.addClient(bank, (Client) in.readObject());
				break;
			case BMSG_ACCOUNT_ADD:
				String clientName = ((Client) in.readObject()).getName();
				bankService.addAccount(bankService.getClientByName(bank, clientName), (AbstractAccount) in.readObject());
				break;
			case BMSG_CLIENT_GET:
				String name = (String) in.readObject();
				out.writeObject(bankService.getClientByName(bank, name));
				break;
			case BMSG_BYE:
				isStopped = true;
				break;
			default:
				System.out.println("Unknow message format");
			}
		} catch (ClientExistsException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (AccountExistsException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(final String args[]) {
		BankServer server = new BankServer(9999);
		server.run();
	}
}
